import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;
import com.mxgraph.model.mxCell;
import com.mxgraph.util.mxConstants;
import com.Ostermiller.util.CSVParser;
import java.io.FileInputStream;
import java.util.ArrayList;

public class GraphPlotter
{
    // Anfang Attribute
    private mxGraph graph;
    private Object parent;
    private mxGraphComponent graphComponent;
    private Adjazenzliste adList;
    private int knotenZaehler;
    private Object[] knoten;
    // Ende Attribute

    public GraphPlotter()
    {
        graph = new mxGraph();
        graph.setCellsEditable(false);
        parent = graph.getDefaultParent();
        adList = new Adjazenzliste();
        knotenZaehler = 1;
        knoten = new Object[100];
    }
    // Anfang Komponenten
    // Ende Komponenten
    // Anfang Methoden

    public void init() {
        // Panel width=521, height=353
        erstelleKnoten(40,40);
        erstelleKnoten(40,200);
        erstelleKnoten(250,80);
        erstelleKnoten(200,200);
        erstelleKante(knoten[1], knoten[2], "6");
        erstelleKante(knoten[1], knoten[3], "20");
        erstelleKante(knoten[2], knoten[3], "13");
        erstelleKante(knoten[2], knoten[4], "7");
        erstelleKante(knoten[3], knoten[4], "12");
        erstelleKante(knoten[4], knoten[1], "5");
    }

    public Adjazenzliste getAdListe() {
        return adList;
    }

    public void faerbeKnoten (int knotenNummer, String farbe) {
        graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, farbe, new Object[]{knoten[knotenNummer]}); //changes the color to green
        graphComponent.refresh();
    }

    public Object getSelectedKnoten () {
        if(graph.getModel().isVertex(graph.getSelectionCell()))
            return graph.getSelectionCell();
        else return null;
    }

    public Object[] getSelectedKnotenListe () {
        Object[] o = graph.getSelectionCells();
        if(o.length>1 && graph.getModel().isVertex(o[0]) && graph.getModel().isVertex(o[1])) return o;
        else return null;
    }

    public Object getSelectedKante () {
        if(graph.getModel().isEdge(graph.getSelectionCell()))
            return graph.getSelectionCell();
        else return null;
    }

    public Object[] getSelectedListe () {
        Object[] o = graph.getSelectionCells();
        if(o != null) return o;
        else return null;
    }

    public Object erstelleKnoten(int x, int y) {
        graph.getModel().beginUpdate();
        Object o=null;
        try
        {
            String s = "K"+knotenZaehler;
            o=graph.insertVertex(parent, null, s, x, y, 30, 30, "shape=ellipse;perimeter=ellipsePerimeter");
            knoten[knotenZaehler]=o;
            knotenZaehler++;
            adList.addKnoten(new Knoten(s));
        }
        finally
        {
            graph.getModel().endUpdate();
            return o;
        }
    }

    public Object entferneKnoten(Object k) {
        graph.getModel().beginUpdate();
        Object o=null;
        try
        {
            if(graph.getModel().isVertex(k)){
                o = graph.getModel().remove(k);
                if (adList.isKnotenEnthalten(String.valueOf(graph.getModel().getValue(k))))
                    adList.removeKnoten(adList.getKnoten(String.valueOf(graph.getModel().getValue(k))));
            }
        }
        finally
        {
            graph.getModel().endUpdate();
            return o;
        }
    }

    public Object erstelleKante(Object k1, Object k2, String gewicht) {
        graph.getModel().beginUpdate();
        Object o=null;
        try
        {
            if(graph.getModel().isVertex(k1) && graph.getModel().isVertex(k2)){
                o = graph.insertEdge(parent, null, gewicht, k1, k2);
                if(!adList.isKanteEnthalten(String.valueOf(graph.getModel().getValue(k1)),
                    String.valueOf(graph.getModel().getValue(k2)),gewicht)){
                    adList.addKante(adList.getKnoten(String.valueOf(graph.getModel().getValue(k1))),
                        adList.getKnoten(String.valueOf(graph.getModel().getValue(k2))),Double.valueOf(gewicht));
                }
            }
        }
        finally
        {
            graph.getModel().endUpdate();
            return o;
        }
    }

    public Object entferneKante(Object k) {
        graph.getModel().beginUpdate();
        Object o=null;
        try
        {
            if(graph.getModel().isEdge(k)){
                Object source = ((mxCell)k).getSource();
                Object target = ((mxCell)k).getTarget();
                String v1Name = (((mxCell)source).getValue()).toString();
                String v2Name = (((mxCell)target).getValue()).toString();
                double gewicht = Double.valueOf(String.valueOf(graph.getModel().getValue(k)));
                // System.out.println("Source: "+v1Name+", Target: "+v2Name);
                Knoten v1 = adList.getKnoten(v1Name);
                Knoten v2 = adList.getKnoten(v2Name);
                // System.out.println(v1.toString()+"; "+v2.toString());
                o = graph.getModel().remove(k);
                Kante e = adList.getKante(v1, v2, gewicht);
                // System.out.println("Gewicht: "+gewicht);
                adList.removeKante(e);
            }
        }
        finally
        {
            graph.getModel().endUpdate();
            return o;
        }
    }

    public Object[] zweiKnotenEineKante(int x1, int y1,int x2, int y2, String gewicht) {
        graph.getModel().beginUpdate();
        Object[] ol = null;
        try
        {
            ol = new Object[3];
            ol[0] = erstelleKnoten(x1, y1);
            ol[1] = erstelleKnoten(x2, y2);
            ol[2] = erstelleKante(ol[0], ol[1], gewicht);
        }
        finally
        {
            graph.getModel().endUpdate();
            return ol;
        }
    }

    public boolean loescheGraph() {
        graph.getModel().beginUpdate();
        boolean geschafft = false;
        try
        {
            graph.selectAll();
            Object[] selected = getSelectedListe();
            for(Object o : selected){
                if(graph.getModel().isVertex(o)) entferneKnoten(o);
                if(graph.getModel().isEdge(o)) entferneKante(o);
            }
            knotenZaehler = 1;
            geschafft = true;
        }
        finally
        {
            graph.getModel().endUpdate();
            return geschafft;
        }
    }

    public boolean csvDateiEinlesen() {
        return csvDateiEinlesen("graph.csv");
    }

    /*
     * Datei in der Notation als Adjazenzmatrix mit Kommagetrennten Werten wird eingelesen
     */
    public boolean csvDateiEinlesen(String dateiName) {
        boolean geschafft = false;
        try {
            CSVParser csvParser = new CSVParser( new FileInputStream(dateiName) );
            String[][] matrix = csvParser.getAllValues();
            int xOffset=50, yOffset=50;
            int xDelta=0, yDelta=0;
            int knotenAnzahl=0;
            int zeilenumbruch=0, umbruch=0;
            if(loescheGraph()) geschafft = true;
            // Knoten zaehlen
            for(String[] row : matrix)
            {
                knotenAnzahl++;
            }
            switch (knotenAnzahl) {
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                umbruch = 2;
                break;
                case 7:
                case 8:
                case 9:
                umbruch = 3;
                break;
                case 10:
                case 11:
                case 12:
                umbruch = 4;
                break;
                case 13:
                case 14:
                case 15:
                case 16:
                case 17:
                case 18:
                case 19:
                case 20:
                umbruch = 5;
                break;
                default:
                umbruch = ((int)knotenAnzahl/6)+2;
            }

            // Knoten erstellen
            for(String[] row : matrix)
            {
                erstelleKnoten(xOffset+xDelta, yOffset+yDelta);
                xDelta+=80;
                zeilenumbruch++;
                if (zeilenumbruch%umbruch==0) {
                    xDelta=0;
                    yDelta+=100;
                }
            }

            // Kanten erstellen
            for(int i = 0; i < matrix.length; i++)
            {
                String[] row = matrix[i];
                for(int j = 0; j < row.length; j++)
                {
                    if(row[j]!="") erstelleKante(knoten[i+1],knoten[j+1],row[j]);
                }
            }
        }
        catch (Exception e){geschafft = false;}
        return geschafft;
    }

    public mxGraph getGraph() {
        return graph;
    }

    public Object getParent() {
        return parent;
    }

    public mxGraphComponent getGraphComponent() {
        return graphComponent;
    }

    public void setGraphComponent(mxGraphComponent graphComponent) {
        this.graphComponent = graphComponent;
    }

    // Ende Methoden
}